/*
 * Copyright 2008-2013 Freescale Semiconductor, Inc.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include "flib/rta.h"
#include "test_common.h"

enum rta_sec_era rta_sec_era;

int deco_dma(uint32_t *buff)
{
	struct program prg;
	struct program *p = &prg;
	int data_size = 7040;
	int move_size = 128;	/* how many bytes to load/store at a time */
	uint64_t input = (uint64_t) 0x32a8ce00ull;
	uint64_t output = (uint64_t) 0x6d045800ull;

	LABEL(loop);
	REFERENCE(pjump1);
	LABEL(done_full);
	REFERENCE(pjump2);

	PROGRAM_CNTXT_INIT(p, buff, 0);
	PROGRAM_SET_36BIT_ADDR(p);
	if (need_bswap)
		PROGRAM_SET_BSWAP(p);
	/*
	 * Job to perform DMA on SEC Era 2 (and later) platforms
	 * input/output/data_size configure the data to be moved.  move_size
	 * is to set the 'chunk' size.  Up to a limit, this determines how
	 * fast the movement will take place.  Beyond that limit, the
	 * Descriptor might not work.  move_size must be a multiple of 8.
	 */
	JOB_HDR(p, SHR_NEVER, 0, 0, 0);
	{
		/*
		 * Set up the ins and outs.  These two Commands could be in a
		 * Job Descriptor (with REO), with the rest of the commands in
		 * a Shared Descriptor.
		 */
		SEQINPTR(p, input, data_size, EXT);
		SEQOUTPTR(p, output, data_size, EXT);

		/* Calculate how much data there is */
		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ, 4, 0);

		/*
		 * Start the Burster doing reads and writes.  Input data will
		 * go to the Class 1 Alignment Block.
		 */
		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1);
		SEQFIFOSTORE(p, MSG, 0, 0, VLF);

		/*
		 * We don't want info-fifo entries to be generated by the MOVEs
		 * from 'ififoab1', as the data is already going to the Class 1
		 * Alignment Block because of the seqfifoload, above.
		 */
		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);

		/* Put MOVE length (chunk size) into Math 1 */
		MATHB(p, ZERO, ADD, move_size, MATH1, 4, IMMED2);

		/*
		 * Put the last MOVE and HALT commands into Math 3
		 * RTA does not support generating MATH commands with LEN = 8
		 * and no immediate inlined in the command, thus use WORD(p, ).
		 */
		WORD(p, 0xa80c4308);
		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, VLF | IMMED);
		JUMP(p, 0, HALT_STATUS, ALL_TRUE, 0);

		SET_LABEL(p, loop);	/* size each full transfer */
		MATHB(p, VSEQINSZ, SUB, MATH1, NONE, 4, 0);
		pjump2 = JUMP(p, done_full, LOCAL_JUMP, ANY_TRUE,
			      MATH_N | MATH_Z);

		/* Move a 'full chunk' */
		MOVE(p, IFIFOAB1, 0, OFIFO, 0, move_size, VLF | IMMED);
		MATHB(p, VSEQINSZ, SUB, MATH1, VSEQINSZ, 4, 0);
		pjump1 = JUMP(p, loop, LOCAL_JUMP, ALL_TRUE, 0);

		SET_LABEL(p, done_full); /* Only last partial xfer remaining */
		/*
		 * Update the last MOVE command and move it and JUMP commands
		 * to head of descriptor buffer
		 */
		MATHB(p, VSEQINSZ, LSHIFT, 32, MATH1, 8, IFB | IMMED2);
		MATHB(p, MATH1, OR, MATH3, MATH3, 8, 0);
		MOVE(p, MATH3, 0, DESCBUF, 0, 8, WAITCOMP | IMMED);
		JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
	}
	PATCH_JUMP(p, pjump1, loop);
	PATCH_JUMP(p, pjump2, done_full);

	return PROGRAM_FINALIZE(p);
}

uint32_t prg_buff[1000];

int main(int argc, char **argv)
{
	int size;

	pr_debug("DECO DMA example program\n");
	rta_set_sec_era(RTA_SEC_ERA_3);
	size = deco_dma(prg_buff);
	pr_debug("size = %d\n", size);
	print_prog(prg_buff, size);

	return 0;
}
